using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using MJB.UI.ContentEditor.Document;

namespace MJB.UI.ContentEditor.Windows
{
    /// <summary>
    /// Interaction logic for KeyWordGeneratorWindow.xaml
    /// </summary>
    public partial class KeyWordGeneratorWindow : Window
    {
        #region Member Variables

        /// <summary>
        /// This is a list of found keywords.
        /// </summary>
        private ObservableCollection<KeyWord> mFoundKeywordList;

        /// <summary>
        /// This is a list of keywords that we selected.
        /// </summary>
        private ObservableCollection<KeyWord> mSelectedKeywords;

        #endregion
        #region Constructor

        /// <summary>
        /// Generates the keywords.
        /// </summary>
        public KeyWordGeneratorWindow()
        {
            mFoundKeywordList = new ObservableCollection<KeyWord>();
            mSelectedKeywords = new ObservableCollection<KeyWord>();
            InitializeComponent();
        }

        #endregion
        #region Public Methods

        /// <summary>
        /// Returns the selected keywords.
        /// </summary>
        /// <returns></returns>
        public string GetSelectedKeyWords()
        {
            if(mSelectedKeywords.Count == 0)
                return null;

            StringBuilder stringBuilder = new StringBuilder();
            for(int i = 0; i < mSelectedKeywords.Count; i++)
            {
                stringBuilder.Append(mSelectedKeywords[i].Word);
                if(i < mSelectedKeywords.Count - 1)
                    stringBuilder.Append(", ");

            }

            return stringBuilder.ToString();

        }

        /// <summary>
        /// Sets the document reader.
        /// </summary>
        public void SetDocumentReader(IDocumentReader documentReader)
        {
            SortedDictionary<string, int> wordCount = new SortedDictionary<string, int>();

            // Go through each section:
            foreach(ISection section in documentReader.Sections)
            {
                // Read just the text:
                string text = String.Empty;
                XmlTextReader xmlReader = null;

                try
                {
                    // Read the content from memory:
                    byte[] bytes = Encoding.Default.GetBytes(section.SectionText);
                    MemoryStream memoryStream = new MemoryStream(bytes);

                    // The xml reader will skip over the elements / attributes for us:
                    XmlParserContext parserContext = new XmlParserContext(null, null, null, XmlSpace.None);
                    xmlReader = new XmlTextReader(memoryStream, XmlNodeType.Element, parserContext);

                    // Read all of the text nodes:
                    StringBuilder stringBuilder = new StringBuilder();
                    while(xmlReader.Read())
                    {
                        if(xmlReader.NodeType == XmlNodeType.Text)
                        {
                            stringBuilder.Append(xmlReader.Value.ToLower());
                            stringBuilder.Append(" ");
                        }
                    }

                    text = stringBuilder.ToString();

                }
                catch(Exception e)
                {
                    MessageBox.Show(e.Message);
                    throw;
                }
                finally
                {
                    if(xmlReader != null)
                        xmlReader.Close();
                }

                // Count the number of words in this section:
                string[] words = text.Split(' ', '\r', '\n');
                foreach(string currentWord in words)
                {
                    string word = currentWord.Trim('.', ',', ':', ';', '-', '?', '!', '\'', ' ', '"', ')', '(');
                    if(word.Length == 0)
                        continue;

                    if(wordCount.ContainsKey(word))
                    {
                        int count = wordCount[word];
                        wordCount[word] = count + 1;
                    }
                    else
                        wordCount.Add(word, 1);

                }

            }

            // Add to the keywords list:
            List<KeyWord> keyWords = new List<KeyWord>();
            foreach(string word in wordCount.Keys)
            {
                KeyWord keyWord = new KeyWord();
                keyWord.Word = word;
                keyWord.Length = word.Length;
                keyWord.Count = wordCount[word];
                keyWords.Add(keyWord);
            }

            // Now: sort the list!
            keyWords.Sort(delegate(KeyWord word1, KeyWord word2)
            {
                // A word larger than 7 characters is always greater than
                // a word less than five characters:
                if(word1.Length > 7 && word2.Length < 7)
                {
                    return -1;                    
                }
                // The flip side is also true:
                else if(word1.Length < 7 && word2.Length > 7)
                {
                    return 1;

                }
                else if(word1.Length > 7 && word2.Length > 7)
                {
                    // As long as their length's aren't equal, compare
                    // by the length:
                    if(word2.Length != word1.Length)
                        return word2.Length - word1.Length;

                }

                // A higher count is better:
                return word2.Count - word1.Count;

            });

            // Add to the observable collection:
            foreach(KeyWord keyWord in keyWords)
                mFoundKeywordList.Add(keyWord);

            // Now: take the first 300 characters worth of keywords from the sorted list:
            int totalLength = 0;
            foreach(KeyWord keyWord in keyWords)
            {
                if(totalLength < 300)
                {
                    mSelectedKeywords.Add(keyWord);
                    totalLength += keyWord.Length;
                }

                if(totalLength > 300)
                    break;

            }

        }

        #endregion
        #region Event Handlers

        /// <summary>
        /// Called when the window is loaded.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnLoaded(object o, EventArgs args)
        {
            mFoundKeywordsListBox.ItemsSource = mFoundKeywordList;
            mSelectedKeywordsListBox.ItemsSource = mSelectedKeywords;
        }

        /// <summary>
        /// Called when the move up button is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnMoveUpButtonClicked(object o, EventArgs args)
        {
            KeyWord selectedItem = (KeyWord)mSelectedKeywordsListBox.SelectedItem;
            if(selectedItem == null)
                return;

            mSelectedKeywords.Remove(selectedItem);

        }

        /// <summary>
        /// Called when the move down button is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnMoveDownButtonClicked(object o, EventArgs args)
        {
            KeyWord selectedItem = (KeyWord)mFoundKeywordsListBox.SelectedItem;
            if(selectedItem == null)
                return;

            if(!mSelectedKeywords.Contains(selectedItem))
                mSelectedKeywords.Add(selectedItem);

        }

        /// <summary>
        /// Called when the OK button is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnOKButtonClicked(object o, EventArgs args)
        {
            this.Close();
        }

        /// <summary>
        /// Called when the Cancel button is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnCancelButtonClicked(object o, EventArgs args)
        {
            mSelectedKeywords.Clear();
            this.Close();
        }

        #endregion

    }

}